<template>
  <a-button type="primary" style="margin-left: 10px" v-if="RightMenu.hiddenColumns?.length" @click="RightMenu.visibleHideManage = true">
    隐藏列管理
  </a-button>
  <!-- 跳转指定行 -->
  <div class="c__my_s_table">
    <a-modal v-model:open="Table.visibleDelete" @ok="Table.handleDeleteConfirm">是否删除？</a-modal>
    <!-- 隐藏列管理 -->
    <a-modal v-model:open="RightMenu.visibleHideManage" @ok="RightMenu.visibleHideManage = false">
      <div style="height: 40px"></div>
      <template v-for="(item, index) in RightMenu.hiddenColumns" :key="index">
        <div class="hide_column">
          <div class="hide_column--col">{{ item }}</div>
          <div class="hide_column--btn">
            <a-button type="primary" size="small" @click="RightMenu.handleHideColumnShow(item)">显示列</a-button>
          </div>
        </div>
        <div v-if="index < RightMenu.hiddenColumns?.length - 1" class="hide_column_gap"></div>
      </template>
      <div style="height: 20px"></div>
    </a-modal>

    <s-table
      v-if="Root.visible"
      v-bind="props"
      :ref="Table.ref.set"
      :columns="Table.columns"
      :data-source="Table.dataSource"
      :scroll="{ x: scroll?.x ?? 0, y: Root.tableHeight }"
      :row-selection="canRowSelect ? Table.rowSelection : false"
    >
      <!-- 🍢# 筛选下拉模板 -->
      <template #customFilterDropdown="{ confirm, column }: { confirm: () => void; column: IColumn }">
        <div class="custom_filter">
          <!-- 字典模板 -->
          <div v-if="column.filter?.dict">
            <a-checkbox-group v-model:value="Filter.fieldsDict[column.dataIndex]" :options="column.filter?.options" />
            <div class="custom_filter--control">
              <a-button size="small" type="default" :disabled="!Filter.fieldsDict[column.dataIndex]?.length" @click="Filter.handleReset(column)">
                <span>重置</span>
              </a-button>
              <a-button size="small" type="primary" @click="Filter.handleFilter(confirm)">确定</a-button>
            </div>
          </div>
          <!-- 关键字模板 -->
          <div v-if="column.filter?.type === `keyword`">
            <a-input placeholder="请输入关键字" v-model:value="Filter.fieldsKeyword[column.dataIndex]"></a-input>
            <div class="custom_filter--control">
              <a-button size="small" type="default" :disabled="!Filter.fieldsKeyword[column.dataIndex]" @click="Filter.handleReset(column)">
                <span>重置</span>
              </a-button>
              <a-button size="small" type="primary" @click="Filter.handleFilter(confirm)">确定</a-button>
            </div>
          </div>
          <!-- 数字范围模板 -->
          <div v-if="column.filter?.type === `rangeNumber`">
            <div class="custom_filter--range">
              <a-input-number placeholder="请输入" v-model:value="Filter.fieldsRangeNumber[column.dataIndex].start"></a-input-number>
              <span>至</span>
              <a-input-number placeholder="请输入" v-model:value="Filter.fieldsRangeNumber[column.dataIndex].end"></a-input-number>
            </div>
            <div class="custom_filter--control">
              <a-button
                size="small"
                type="default"
                :disabled="Filter.fieldsRangeNumber[column.dataIndex].start === `` && Filter.fieldsRangeNumber[column.dataIndex].end === ``"
                @click="Filter.handleReset(column)"
              >
                <span>重置</span>
              </a-button>
              <a-button size="small" type="primary" @click="Filter.handleFilter(confirm)">确定</a-button>
            </div>
          </div>
          <!-- 结果分类模板 -->
          <div v-if="column.filter?.type === `classification`">
            <a-checkbox-group v-model:value="Filter.fieldsClassification[column.dataIndex]" :options="column.filter?.options" />
            <div class="custom_filter--control">
              <a-button
                size="small"
                type="default"
                :disabled="!Filter.fieldsClassification[column.dataIndex]?.length"
                @click="Filter.handleReset(column)"
              >
                <span>重置</span>
              </a-button>
              <a-button size="small" type="primary" @click="Filter.handleFilter(confirm)">确定</a-button>
            </div>
          </div>
        </div>
      </template>
      <template #customFilterIcon="{ filtered }">
        <SearchOutlined :style="{ color: filtered ? '#108ee9' : undefined }" />
      </template>

      <!-- 🍢# 列模板 -->
      <template #bodyCell="cell">
        <template v-if="cell">
          <!-- 删除行按钮列 -->
          <a-popconfirm v-if="cell?.column.dataIndex === `_delete`" title="是否删除?" @confirm="Table.handleDelete(cell)">
            <a-button type="link" :danger="true">删除</a-button>
          </a-popconfirm>
          <!-- 显示上传图片列 -->
          <template v-else-if="props.imageColumns.includes(`${cell?.column.dataIndex ?? ``}`)">
            <a-image :src="'http://resource.madoka.cn/service/files/' + cell?.text ?? ``"></a-image>
          </template>
          <!-- 自定义列（单列） -->
          <div v-else-if="slots[`${cell?.column.dataIndex}` ?? ``]">
            <slot :name="`${cell?.column.dataIndex}` ?? ``" :cell="cell"></slot>
          </div>
          <!-- 自定义列（所有） -->
          <slot v-else name="_bodyCell" :cell="cell"></slot>
        </template>
      </template>

      <!-- 🍢# 双击编辑模板 -->
      <template #cellEditor="cell">
        <template v-if="cell">
          <!-- 上传-->
<!--          <my-uploader-for-s-table
            :action="`${host}/white/sysImg/upload`"
            v-if="props.imageColumns.includes(`${cell?.column.dataIndex ?? ``}`)"
            :cell="cell"
          >
          </my-uploader-for-s-table>-->
          <!-- 自定义编辑 -->
          <slot v-if="props.customEditColumns.includes(`${cell.column.dataIndex ?? ``}`)" name="_cellEditor" :cell="cell"></slot>
        </template>
      </template>

      <!-- 🍢# 右键菜单模板-->
      <template #contextmenuPopup="args">
        <ul class="popup">
          <li class="popup-item" :class="args?.column?.key === 'operation' && 'disabled'" @click="RightMenu.handleBtnClick(args, 'hide_col')">
            <copy-outlined />
            <span>隐藏当前列</span>
          </li>
        </ul>
      </template>
      <!-- 🍢# 加号展开模板 -->
      <template #expandedRowRender="cell" v-if="slots.expandedRowRender">
        <template v-if="cell">
          <slot name="expandedRowRender" :cell="cell"></slot>
        </template>
      </template>
    </s-table>
    <div v-else class="error_label">&lt;my-s-table&gt;数据不合法，请检查</div>
  </div>
</template>
<script setup lang="ts">
import type { ColumnType, ColumnsType, ContextmenuPopupArg, DefaultRecordType } from "@surely-vue/table/dist/src/components/interface";
import type { DataType } from "vue-request";
import type { IColumn, IObj } from "@/types";
import { CopyOutlined, SearchOutlined } from "@ant-design/icons-vue";
import { STable } from "@surely-vue/table";
import { cloneDeep } from "lodash";
import {removeWatermark, getDictList, host, useReactiveHeight} from "@/utils/common";
import { message } from "ant-design-vue";
import { useLocalStorage } from "@vueuse/core";
import {useSlots} from "vue";
import { deleteWatermark } from "@/common";

const slots = useSlots();
const emit = defineEmits(["row-selected", "row-deleted", "rows-deleted", "row-added", "filter-changed"]);
const props = defineProps({
  // 本地缓存key（必须保证全局唯一）
  localStorageKey: { default: "" },
  // 数据源主键
  primaryKey: { default: "id" },
  // 是否自动高度
  autoHeaderHeight: { default: true },
  // 是否允许多行选择
  canRowSelect: { default: false },
  // 是否允许列拖拽
  columnDrag: { default: true },
  // 是否分页
  pagination: { default: false },
  // 是否显示边框
  bordered: { default: true },
  // 是否可删除（针对行）
  rowDeletable: { default: false },
  // 是否可编辑（针对所有列）
  editable: { default: true },
  // 筛选模式（前端/后端）
  filterMode: { default: "frontend" as "frontend" | "backend" },
  //后端筛选字段
  backendArrays: { default: [] as string[] },
  // 滚动条配置
  scroll: { default: undefined as IObj | undefined },
  // 字体大小
  fontSize: { default: 14 },
  // 表格数据
  dataSource: { default: [] as DefaultRecordType[] },
  // 列数组（筛选项配置请参考IColumn的filter定义）
  columns: { default: [] as IColumn[] },
  // 隐藏的列[字符串数组]
  hideColumns: { default: [] as string[] },
  // 可编辑的列[字符串数组]（可覆盖针对所有列的editable）
  editableColumns: { default: [] as string[] },
  // 不可编辑的列[字符串数组]（可覆盖针对所有列的editable）
  uneditableColumns: { default: [] as string[] },
  // 自定义编辑的列[字符串数组]
  customEditColumns: { default: [] as string[] },
  // 图片的列[字符串数组]
  imageColumns: { default: [] as string[] },
  // 自定义保存方法
  valueSetter: { default: undefined as Function | undefined },
});

const Root = reactive({
  visible: true,
  tableHeight: useReactiveHeight(props.scroll?.y ?? 0),
  columnsSaveTimer: null as any,

  checkTheKey() {
    const dataSourceWithKey = Table.dataSource?.filter((item) => item.key !== undefined) ?? [];
    if (dataSourceWithKey.length !== Table.dataSource?.length) {
      message.error(
        `请设置dataSource每一项的key值或指定主键（主键默认为id）（无效项有${(Table.dataSource?.length ?? 0) - dataSourceWithKey.length}条）`,
      );
      Root.visible = false;
    }
  },
  setSaveTimer() {
    Root.columnsSaveTimer = setInterval(() => {
      Table.localColumns = Table.columns.map((item) => ({ key: `${item.key}`, width: item.width ?? 100 }));
    }, 500);
    onUnmounted(() => {
      clearTimeout(Root.columnsSaveTimer);
    });
  },
  checkLocalStorageKey() {
    if (props.localStorageKey === "") {
      message.error("请设置s-table的local-storage-key");
      Root.visible = false;
    }
  },
  setWatchers() {
    watch(() => props.columns, Table.setNewColumns, { deep: true });
    watch(() => props.dataSource, Table.setNewColumns, { deep: true });
    watch(() => props.dataSource, Filter.filterDataSource, { deep: true });
    watch(() => RightMenu.hiddenColumns, Table.setNewColumns, { deep: true });
    watchEffect(() => {
      Filter.filterDataSource();
      Root.checkTheKey();
    });
    Table.setNewColumns();
  },
  init() {
    onMounted(deleteWatermark);
    Root.setSaveTimer();
    Root.checkLocalStorageKey();
    Root.setWatchers();
  },
});
/**
 * 右键菜单模块
 */
const RightMenu = reactive({
  visibleHideManage: false,
  hiddenColumns: useLocalStorage(`my_s_table_hidden_columns_${props.localStorageKey}`, [] as (string | number)[]),

  handleBtnClick(args?: ContextmenuPopupArg<DefaultRecordType, ColumnType<DefaultRecordType>>, type?: "hide_col" | "add_row") {
    // 右键菜单：隐藏列
    if (type === "hide_col") {
      if (args?.column?.key && !(args?.column?.key === "operation")) {
        RightMenu.hiddenColumns.push(args.column?.key);
      }
    }
    // 右键菜单：新增一行
    if (type === "add_row") {
      if (args?.column?.key && !(args?.column?.key === "operation")) {
        const index = props.dataSource?.findIndex((item) => item[props.primaryKey] === args?.record?.[props.primaryKey]);
        emit("row-added", { row: args?.record, index });
      }
    }
    args?.hidePopup();
  },
  handleHideColumnShow(key:any) {
    RightMenu.hiddenColumns = RightMenu.hiddenColumns.filter((item) => item !== key);
    if (!RightMenu.hiddenColumns?.length) {
      RightMenu.visibleHideManage = false;
    }
  },
});

const Table = reactive({
  visibleDelete: false,
  columns: [] as ColumnsType<DefaultRecordType>,
  dataSource: [] as IObj[],
  localColumns: useLocalStorage(
    `my_s_table_columns_${props.localStorageKey}`,
    [] as {
      key: string;
      width: number;
    }[],
  ),
  selectedRowKeys: [] as string[],
  selectedRows: [] as DataType[],
  filters: {} as IObj,
  rowSelection: {
    onChange: (selectedRowKeys: string[], selectedRows: DataType[]) => {
      Table.selectedRowKeys = selectedRowKeys;
      Table.selectedRows = selectedRows;
      emit("row-selected", selectedRowKeys, selectedRows);
    },
    selections: [
      {
        key: "odd",
        text: "删除选中",
        onSelect() {
          Table.visibleDelete = true;
        },
      },
    ],
  },
  ref: {
    value: null as any,
    set(value: any) {
      Table.ref.value = value;
    },
  },

  handleDeleteConfirm() {
    emit("rows-deleted", Table.selectedRowKeys, Table.selectedRows);
    Table.visibleDelete = false;
  },
  setNewColumns() {
    let columns = cloneDeep(props.columns);
    columns.forEach((item, index) => {
      item.key = item.dataIndex ?? index;
      item.align = "center"
    });
    const getEditFlag = (dataIndex: string) => {
      if (props.customEditColumns.includes(dataIndex) || props.imageColumns.includes(dataIndex)) {
        return "cellEditorSlot";
      }
      if (props.editableColumns.includes(dataIndex)) {
        return true;
      }
      if (props.uneditableColumns.includes(dataIndex)) {
        return false;
      }
      return props.editable;
    };
    columns = columns.filter(({ dataIndex }) => !props.hideColumns.includes(dataIndex));
    columns = columns.filter(({ dataIndex }) => !RightMenu.hiddenColumns.includes(dataIndex));
    columns = columns.map((col: IColumn) => {
      col.editable = getEditFlag(col.dataIndex);
      if (props.valueSetter) {
        col.valueSetter = props.valueSetter;
      }

      // 筛选功能相关数据赋值
      if (col?.filter?.dict) {
        col.customFilterDropdown = true;
        const options = cloneDeep(getDictList(col.filter.dict));
        col.filter.options = options.map((col) => ({ label: col.name, value: col.key }));
      }
      if (col?.filter?.type === "keyword") {
        col.customFilterDropdown = true;
      }
      if (col?.filter?.type === "rangeNumber") {
        col.customFilterDropdown = true;
        Filter.fieldsRangeNumber[col.dataIndex] = { start: "", end: "" };
      }
      if (col?.filter?.type === "classification") {
        col.customFilterDropdown = true;
        let options = cloneDeep(props.dataSource.map((row) => row[col.dataIndex]));
        options = [...new Set(options)];
        options = options.filter((o) => o !== null && o !== undefined);
        options = options.map((o) => ({ label: o, value: o }));
        //如果没有传入自定义下拉框就用行数据
        if (col.filter.options === undefined) {
          col.filter.options = options;
        }
      }

      return col;
    });
    if (props.rowDeletable) {
      columns.push({
        key: "_delete",
        dataIndex: "_delete",
        title: "删除",
        editable: false,
        width: 100,
      });
    }
    const columnsTmpNew: IColumn[] = [];
    Table.localColumns.forEach((itemLocal) => {
      const foundItem = columns.find((item) => item.key === itemLocal.key);
      if (foundItem) {
        if (itemLocal.width) {
          foundItem.width = itemLocal.width;
        }
        columnsTmpNew.push(foundItem);
        columns = columns.filter((item) => item.key !== itemLocal.key);
      }
    });
    columns = [...columnsTmpNew, ...columns];
    Table.columns = columns;
  },
  handleDelete(cell: any) {
    emit("row-deleted", cell);
  },
});

const Filter = reactive({
  // 给emit传参数用（需要用toRaw转为非响应式对象）
  filterPayload: {
    fieldsDict: {},
    fieldsKeyword: {},
    fieldsRangeNumber: {},
    fieldsClassification: {},
  },
  // 筛选数据
  fieldsDict: {} as { [key: string]: string[] },
  fieldsKeyword: {} as { [key: string]: string },
  fieldsRangeNumber: {} as { [key: string]: { start: number | ""; end: number | "" } },
  fieldsClassification: {} as { [key: string]: string[] },

  filterDataSource() {
    // 🍍 模糊筛选功能 🍍
    const filterListVague = (filterFields: { [key: string]: string[] }, fieldsKey: string) => {
      // 已选择项（数组）
      const selectedOptions: string[] = filterFields[fieldsKey];
      // 筛选后的列表
      const listTotal: DefaultRecordType[] = [];
      // 循环已选择项
      selectedOptions.forEach((selectedOption: string) => {
        // 筛选单个已选择项对应的行数据（模糊匹配，比如a可以匹配a、aa、a,b等所有带a的数据）
        listTotal.push(...list.filter((item) => item[fieldsKey]?.includes(selectedOption)));
      });
      // 去重（每个已选项选择出来的行数据可能有重叠情况，比如a和aa都可以选择出aa，此时就会出现两条aa）
      const listTotalKeys = listTotal.map((o) => o.key);
      const listTotalKeysNoRepeat = [...new Set(listTotalKeys)];
      // 去重后赋值给筛选后的list
      list = listTotalKeysNoRepeat.map((key) => listTotal.find((o) => o.key === key) ?? {});
    };

    let list = cloneDeep(props.dataSource);
    list = list.map((item) => {
      return {
        ...item,
        key: item.key ?? item[props.primaryKey],
      };
    });

    // 过滤字典类型字段
    const keysDict = Object.keys(Filter.fieldsDict);
    keysDict.forEach((key) => {
      if (Filter.fieldsDict[key]?.length) {
        if (props.filterMode === "frontend") {
          filterListVague(Filter.fieldsDict, key);
        }
        Filter.filterPayload.fieldsDict[key] = Filter.fieldsDict[key];
      }
    });

    // 过滤关键字类型字段
    const keysKeyword = Object.keys(Filter.fieldsKeyword);
    keysKeyword.forEach((key) => {
      if (Filter.fieldsKeyword[key]) {
        if (props.filterMode === "frontend") {
          list = list.filter((item) => item[key]?.includes(Filter.fieldsKeyword[key]));
        } else if (!props.backendArrays?.includes(key)) {
          list = list.filter((item) => item[key]?.includes(Filter.fieldsKeyword[key]));
        }
        Filter.filterPayload.fieldsKeyword[key] = Filter.fieldsKeyword[key];
      }
    });

    // 过滤数字范围类型字段
    const keysRangeNumber = Object.keys(Filter.fieldsRangeNumber);
    keysRangeNumber.forEach((key) => {
      const start = Filter.fieldsRangeNumber[key].start;
      const end = Filter.fieldsRangeNumber[key].end;
      if (start !== "" && end !== "") {
        if (props.filterMode === "frontend") {
          list = list.filter((item) => item[key] <= end && item[key] >= start);
        }
        Filter.filterPayload.fieldsRangeNumber[key] = Filter.fieldsRangeNumber[key];
      }
    });

    // 过滤结果分类字段
    const keysClassification = Object.keys(Filter.fieldsClassification);
    keysClassification.forEach((key) => {
      if (Filter.fieldsClassification[key]?.length) {
        if (props.filterMode === "frontend" || !props.backendArrays?.includes(key)) {
          filterListVague(Filter.fieldsClassification, key);
        } else if (!props.backendArrays?.includes(key)) {
          filterListVague(Filter.fieldsClassification, key);
        }
        Filter.filterPayload.fieldsClassification[key] = Filter.fieldsClassification[key];
      }
    });
    Table.dataSource = list;
    emit("filter-changed", toRaw(Filter.filterPayload));
  },
  handleFilter(confirm?: () => void) {
    Filter.filterDataSource();
    confirm?.();
  },
  handleReset(column: IColumn) {
    if (column.filter?.dict) {
      Filter.fieldsDict[column.dataIndex] = [];
    }
    if (column.filter?.type === "keyword") {
      Filter.fieldsKeyword[column.dataIndex] = "";
    }
    if (column.filter?.type === "rangeNumber") {
      Filter.fieldsRangeNumber[column.dataIndex] = { start: "", end: "" };
    }
    if (column.filter?.type === "classification") {
      Filter.fieldsClassification[column.dataIndex] = [];
    }
    Filter.filterDataSource();
  },
});

const css_font_size = computed((): string => `${props.fontSize}px`);

Root.init();

/**
 * 组件暴露方法
 */

</script>
<style lang="less" scoped>
html body .c__my_s_table:deep(.surely-table-cell-content) {
  font-size: v-bind(css_font_size);
}

html body .c__my_s_table:deep(.surely-table-header-cell-title-inner) {
  font-size: v-bind(css_font_size);
}

.error_label {
  text-align: center;
  padding: 80px;
  font-size: 30px;
  color: #0003;
}

.custom_filter {
  padding: 0.6em;
  //
  &:deep(.ant-checkbox-group) {
    display: flex;
    flex-direction: column;
    max-height: 60vh;
    gap: 0;
  }

  &--control {
    display: flex;
    justify-content: flex-end;
    gap: 0.6em;
    margin-top: 0.6em;
  }

  &--range {
    display: flex;
    gap: 0.6em;
    align-items: center;
  }
}

.popup {
  padding: 0;
}

.popup-item {
  padding: 0.8em 1em;
}

.hide_column {
  display: flex;
  padding: 0.4em 1em;
  border-radius: 8px;
  transition: 0.2s;
  //
  &:hover {
    background: #0002;
  }

  &--col {
    flex: 1;
  }
}

.hide_column_gap {
  position: relative;
  height: 8px;
  display: flex;
  align-items: center;
  justify-content: center;

  &::after {
    content: "";
    width: 100%;
    height: 1px;
    background: #0001;
  }
}
</style>
